package modelovectorial;

import modelovectorial.persistencia.DocumentoDB;
import modelovectorial.persistencia.GestorConsultas;
import modelovectorial.persistencia.GestorInsercion;
import soporte.web.Pagination;
import utn.frc.tsb.utils.ValerioFritelli.HashTable.HashList;
import utn.frc.tsb.utils.ValerioFritelli.SimpleList.SimpleList;
import utn.frc.tsb.utils.ValerioFritelli.SortMethods.QuickSortComparable;

/**
 * @project DLC Final / UTN FRC 2013
 * @date Febrero de 2013
 *
 * @author Gonzalo Arribere
 * @author Gustavo Morales
 * @author Pablo Moreno
 *
 * Esta clase representa un documento PDF de la base de datos.
 */
public class DocumentoPDF implements Comparable, QuickSortComparable {
    
    // radio de alcance del fragmento que se tomara a partir del termino buscado
    // Google Style = 14
    public static final int INDEX_OFFSET_RADIUS = 14; 
    // formato de la representacion del TFIDF
    public static final String TFIDF_FORMAT = "%.4f";
    // formato de tamaño en megabytes.
    public static final String MB_EXTENSION = "%d MB";
    public static final String KB_EXTENSION = "%d KB";
    private int idDocument = 0;
    private String nombre = "desconocido";
    private String autor = "desconocido";
    private String ruta = "desconocida";
    private int paginas = 0;
    // tamaño del archivo en bytes
    private long longitud = 0;
    private int maxTf = 0;
    
    // mWords: deberia ser reemplazado por una doble indexacion que permita una
    // busqueda rapida (para no perder tiempo mientras se leen las palabras del
    // PDF - recorrido total sin overwork (para cuando hay que guardar en la DB)
    private HashList mWords;
    // Fragmento de texto a construir *
    private String mFragment;
    // Menor indice encontrado en los terminos buscados 0 en caso de no
    // encontrarse en la Indexacion parcial (3K indices)
    private int mMinIndex;
    // TFIDF calculado para el documento
    private double mTFIDF;

    /**
     * Constructor de la clase Documento que recibe por parametro el id del
     * documento.
     *
     * @param pIdDocument entero que representa el identificador del documento
     * en la bd.
     */
    public DocumentoPDF(int pIdDocument) {
        idDocument = pIdDocument;
    }

    /**
     * Constructor de la clase Documento que recibe por parametro el id del
     * documento y la mayor frecuencia que un termino obtuvo en el documento.
     *
     * @param pIdDocument entero que representa el identificador del documento
     * en la bd.
     * @param pMaxTF entero que representa la maxima frecuencia de un termino en
     * el documento.
     */
    public DocumentoPDF(int pIdDocument, int pMaxTF) {
        idDocument = pIdDocument;
        maxTf = pMaxTF;
        mWords = new HashList(50);
    }

    /**
     * Constructor de la clase Documento que recibe por parametro el id del
     * documento, la mayor frecuencia que un termino obtuvo en el documento y el
     * menor indice de cualquiera de los terminos de una consulta.
     *
     * @param pIdDocument pIdDocument entero que representa el identificador del
     * documento en la bd.
     * @param pMaxTF entero que representa la maxima frecuencia de un termino en
     * el documento.
     * @param pMinIndex entero que representa el menor indice de cualquiera de
     * los terminos de una consulta.
     */
    public DocumentoPDF(int pIdDocument, int pMaxTF, int pMinIndex) {
        idDocument = pIdDocument;
        maxTf = pMaxTF;
        mWords = new HashList(50);
        mMinIndex = pMinIndex;
    }

    /**
     * Constructor de la clase Documento que recibe por parametro valores para
     * los atributos del documento.
     *
     * @param nombre cadena que representa el nombre del documento pdf.
     * @param autor cadena que representa el nombre del autor del documento.
     * @param ruta cadena que representa la ruta donde se ubica el documento en
     * disco.
     * @param paginas entero que representa la cantidad de paginas que tiene el
     * documento.
     * @param longitud entero largo que representa el tamanio en bytes del
     * documento.
     * @param maximaFrecuencia entero que representa la maxima frecuencia de un
     * termino en el documento.
     */
    public DocumentoPDF(int idDocument, String nombre, String autor, String ruta, int paginas, int pMaxTF, int pSize, boolean OK) {
        this.idDocument = idDocument;
        this.nombre = nombre;
        this.autor = autor;
        this.ruta = ruta;
        this.paginas = paginas;
        this.maxTf = pMaxTF;
        this.longitud = pSize;
    }

    /**
     * Constructor por parametros que inicializa los atributos de la clase
     *
     * @param idDocumento entero que representa el identificador del documento.
     * @param autor cadena que representa el nombre del autor del documento.
     * @param ruta cadena que representa la ruta donde se ubica el documento en
     * disco.
     * @param paginas entero que representa la cantidad de paginas que tiene el
     * documento.
     * @param longitud entero largo que representa el tamanio en bytes del
     * documento.
     * @param maximaFrecuencia entero que representa la maxima frecuencia de un
     * termino en el documento.
     */
    public DocumentoPDF(String nombre, String autor, String ruta, int paginas, long longitud, int maximaFrecuencia) {
        this.autor = autor;
        this.nombre = nombre;
        this.ruta = ruta;
        this.paginas = paginas;
        this.longitud = longitud;
        this.maxTf = maximaFrecuencia;
    }

    
    public int getMaxTf() {
        return maxTf;
    }

    public void setMaxTf(int maxTf) {
        this.maxTf = maxTf;
    }

    public String getAutor() {
        return autor;
    }

    public void setAutor(String autor) {
        this.autor = autor;
    }

    public int getIdDocument() {
        return idDocument;
    }

    public void setIdDocument(int idDocument) {
        this.idDocument = idDocument;
    }

    public long getLongitud() {
        return longitud;
    }

    /**
     * Devuelve el tamanio en bytes en disco del documento, en formato String.
     *
     * @return una cadena que representa el tamanio en bytes del documento.
     */
    public String getLongitudString() {
        String mLongitud;
        long newLongitud = this.longitud / 1024;
        if (newLongitud < 1024) {
            mLongitud = String.format(KB_EXTENSION, newLongitud);
        } else {
            newLongitud /= 1024;
            mLongitud = String.format(MB_EXTENSION, newLongitud);
        }
        return mLongitud;
    }

    public void setLongitud(long longitud) {
        this.longitud = longitud;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public int getPaginas() {
        return paginas;
    }

    public void setPaginas(int paginas) {
        this.paginas = paginas;
    }

    public String getRuta() {
        return ruta;
    }

    public void setRuta(String ruta) {
        this.ruta = ruta;
    }

    @Override
    public String toString() {
        return "\nNombre del documento: " + nombre + "\nRuta: " + ruta + "\nTamaño en bytes: " + longitud + "\nAutor: " + autor + "\nPáginas: " + paginas;
    }

    /**
     * Graba el documento pdf en la DB.
     */
    public void persistir() {
        GestorInsercion.getInstance().grabarDocumento(this);
        setIdDocument(GestorConsultas.getInstance().getMaxIdDocumento());
    }

    /**
     * Actualiza los datos del documento pdf en la DB.
     */
    public void updatePersistencia() {
        GestorInsercion.getInstance().actualizarDocumento(this);
    }

    /**
     * Redefinicion del metodo hashCode que devuelve el codigo identificador de
     * objeto del documento.
     *
     * @return un entero que representa el valor que identifica al objeto.
     */
    @Override
    public int hashCode() {
        return idDocument;
    }

    /**
     * Determina si el objeto actual es el mismo objeto que el que se recibe por
     * parametro.
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final DocumentoPDF other = (DocumentoPDF) obj;
        if (this.idDocument != other.idDocument) {
            return false;
        }
        return true;
    }

    /**
     * Determina el orden que tiene el objeto actual con respecto al objeto
     * recibido por parametro.
     */
    public int compareTo(Object o) {
        return idDocument - ((DocumentoPDF) o).getIdDocument();
    }

    /**
     * Compara dos objetos teniendo en cuenta el algoritmo de ordenamiento
     * quickSort el cual compara los objetos segun el TFIDF de cada uno.
     */
    public double quickSortCompare(QuickSortComparable x) {
        return (((DocumentoPDF) x).getTfidf() - mTFIDF);
    }

    /**
     * Realiza la suma de todos los pesos de los terminos del documento.
     */
    public void computeTFIDF(int pTotalDocuments) {
        Palabra word;
        mWords.startIterator();

        while (mWords.hasNext()) {
            word = (Palabra) mWords.next();

            mTFIDF +=
                    ((double) word.getTfDoc() / (double) maxTf)
                    * Math.log((double) pTotalDocuments / (double) word.getNr())
                    / Math.log(10);
        }
    }

    /**
     * Devuelve la suma del peso de todos los terminos del documento calculada
     * por la formula del tfidf.
     */
    public double getTfidf() {
        return mTFIDF;
    }

    /**
     * Devuelve la suma del peso de todos los terminos del documento calculada
     * por la formula del tfidf, en formato de String.
     */
    public String getTfidfString() {
        return String.format(TFIDF_FORMAT, mTFIDF);
    }

    /**
     * Limpia la lista de palabras del documento.
     */
    public void clearTerms() {
        mWords = new HashList(10);
    }

    /**
     * Agrega una nueva palabra a la lista de palabras del documento.
     */
    public void addPalabra(int pIdPalabra, int pTF, int pNR) {
        mWords.put(new Palabra(pIdPalabra, pTF, pNR));
    }

    /**
     * Setea el menor indice de cualquiera de los terminos de una consulta.
     */
    public void setMinIndex(int pMinIndex) {
        mMinIndex = pMinIndex;
    }

    /**
     * Devuelve el menor indice de cualquiera de los terminos de una consulta.
     */
    public int getMinIndex() {
        return mMinIndex;
    }

    /**
     * Devuelve los documentos guardados en ls bd que se corresponden con los
     * documentos pasados por parametro.
     */
    public static HashList getDocuments(DocumentoPDF[] pDocument, Pagination pPagination) {
        return DocumentoDB.getDocuments(pDocument, pPagination);
    }

    /**
     * Setea el fragmento de texto que se mostrara en la busqueda asociado al
     * docuemnto elegido por el motor.
     */
    public void setDocumentFragment(String pFragment) {
        mFragment = pFragment;
    }

    /**
     * Devuelve la cantidad total de documentos guardados en la bd.
     */
    public static int getTotalDocuments() {
        return DocumentoDB.getTotalDocuments();
    }

    /**
     * Copia los valores de un documento guardado en la base de datos al objeto
     * Documento actual.
     */
    public void copy(DocumentoPDF pDocument, boolean pSkypIndex) {
        setAutor(pDocument.getAutor());
        setNombre(pDocument.getNombre());
        setLongitud(pDocument.getLongitud());
        setRuta(pDocument.getRuta());
        setPaginas(pDocument.getPaginas());
        if (!pSkypIndex) {
            setMinIndex(pDocument.getMinIndex());
        }
    }

    /**
     * Busca las palabras en la bd de ese documento, iniciando desde el menor
     * indice (minIndex)
     */
    public void fillTerms(boolean pUseRadiusIndex) {
        DocumentoDB.fillTerms(this, pUseRadiusIndex);
    }

    /**
     * Devuelve el fragmento asociado al documento para mostrar en el resultado
     * de las busquedas.
     */
    public String getDocumentFragment() {
        return mFragment;
    }

    /**
     * Devuelve los mismos documentos pasados por parametro con sus menores
     * indices recuperados de la base de datos.
     */
    public static HashList getDocumentsMinIndex(HashList pDocuments, Pagination pPagination, SimpleList pQuery) {
        return DocumentoDB.getDocumentsMinIndex(pDocuments, pPagination, pQuery);
    }

    public static DocumentoPDF getDocument(int pIdDocumento) {
        return DocumentoDB.readDocument(pIdDocumento);
    }

    public static DocumentoPDF[] getLastDocuments() {
        return DocumentoDB.getLastDocuments();
    }

    public static DocumentoPDF[] browseDocumentos(Pagination pPagination) {
        return DocumentoDB.browseDocuments(pPagination);
    }
}